﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections;

namespace ProtocolCoder
{
    class Generator
    {
        private string output_directory_;
        private Hashtable variables_;
        private Hashtable message_info_from_name_;
        private OutputPrinter Printer;
        private bool IsServerProto;


        public Generator(string OutputDirectory,
                         Hashtable variables,
                         Hashtable MessageInfosFromName, bool ServerProto)
        {
            output_directory_ = OutputDirectory;
            variables_ = variables;
            message_info_from_name_ = MessageInfosFromName;
            IsServerProto = ServerProto;
        }

        /// <summary>
        /// 生成头文件
        /// </summary>
        /// <returns></returns>
        public bool GenerateCSharpFile()
        {
            if (!variables_.ContainsKey("FileName"))
            {
                Console.WriteLine("无法找到与输出文件名称相关的信息");
                return false;
            }
            try
            {
                string filename = output_directory_ + variables_["FileName"] + "X.cs";
                using (StreamWriter sw = new StreamWriter(filename, false, Encoding.UTF8))
                {
                    Printer = new OutputPrinter(sw, '$');
                    Printer.Print("/********************************************************************\n" +
                                  "**       This head file is generated by program,                   **\n" +
                                  "**            Please do not change it directly.                    **\n" +
                                  "**                   Auther: Fu Yifan                              **\n" +
                                  "********************************************************************/\n\n");



                    //Printer.Print(variables_, "import common\nimport $InputFile$_pb2\n\n");
                    #region 生成CS文件
                    #region 命名空间的处理
                    if (variables_["NameSpace"] != null)
                    {
                        Printer.Print(variables_, "namespace $NameSpace$");
                        Printer.Print("{\n");
                        Printer.Indent();
                    }
                    #endregion
                    #region 生成enum声明
                    Printer.Print(variables_, "enum $FileName$_MessageID\n{\n");
                    Printer.Indent();
                    int MaxIndex = Convert.ToInt32(variables_["MaxIndex"]);
                    ArrayList tempList = new ArrayList(MaxIndex + 1);
                    for (int i = 0; i < MaxIndex + 1; i++)
                        tempList.Add(null);
                    foreach (DictionaryEntry de in message_info_from_name_)
                    {
                        MessageInfo info = (MessageInfo)de.Value;
                        tempList[info.ID] = info;
                    }
                    for (int i = 0; i < MaxIndex + 1; i++)
                    {
                        if (tempList[i] != null)
                        {
                            MessageInfo info = (MessageInfo)tempList[i];
                            Printer.Print(String.Format("{0}\t\t\t\t\t= {1},\n", info.Name, info.ID));
                        }
                    }
                    Printer.Print(variables_, "$FileName$MaxMessageID\n");
                    Printer.Outdent();
                    Printer.Print("};\n\n");
                    #endregion


                    Printer.Print(variables_, "class $FactoryName$\n{\n");
                    Printer.Indent();
                    Printer.Print(variables_, "private delegate object DeFuncWS2MSProto(byte[] buf, uint Size, $ProcessorClass$ pProc);\n");
                    Printer.Print(variables_, "private static DeFuncWS2MSProto[] m_DecodeFuncArray = new DeFuncWS2MSProto[(int)$FileName$_MessageID.$FileName$MaxMessageID];\n");
                    #region 协议分发处理函数
                    Printer.Print(variables_, "public static object Decode(uint MsgID, byte[] buf, uint Size, $ProcessorClass$ pProc)\n");
                    Printer.Print("{\n");
                    Printer.Indent();
                    Printer.Print(variables_, "if(MsgID > (int)$FileName$_MessageID.$FileName$MaxMessageID || m_DecodeFuncArray[MsgID] == null){\n");
                    Printer.Indent();
                    Printer.Print("return null;\n");
                    Printer.Outdent();
                    Printer.Print("}\nreturn m_DecodeFuncArray[MsgID](buf, Size, pProc);\n");
                    Printer.Outdent();
                    Printer.Print("}\n\n");
                    #endregion

                    #region 生成构造函数
                    Printer.Print(variables_, "public $FactoryName$()\n{\n");
                    Printer.Indent();
                    foreach (DictionaryEntry de in message_info_from_name_)
                    {
                        MessageInfo info = (MessageInfo)de.Value;
                        if (info.func != null)
                            Printer.Print(variables_, String.Format("m_DecodeFuncArray[(int)$FileName$_MessageID.{0}] = Decode{0};\n", de.Key));
                    }
                    Printer.Outdent();
                    Printer.Print("}\n\n");
                    #endregion

                    #region 生成处理函数
                    foreach (DictionaryEntry de in message_info_from_name_)
                    {
                        MessageInfo info = (MessageInfo)de.Value;
                        if (info.func == null)
                            continue;
                        Printer.Print(variables_, String.Format("private object Decode{0}(byte[] buf, uint Size, $ProcessorClass$ pProc)\n", de.Key) + "{\n");
                        Printer.Indent();

                        if (IsServerProto == info.ByServer)
                        {
                            //info.
                            Printer.Print(String.Format("{0} pkg = {0}.CreateBuilder().MergeFrom(buf).Build();\n", info.Type));
                            Printer.Print(String.Format("return pProc.{0}(pkg);\n", info.func));
                            //Printer.Print("}\n");
                        }
                        else
                            Printer.Print("return null;\n");
                        Printer.Outdent();
                        Printer.Print("}\n\n");
                    }
                    #endregion

                    Printer.Outdent();
                    Printer.Print("}\n");

                    #region 命名空间的处理
                    if (variables_["NameSpace"] != null)
                    {
                        Printer.Outdent();
                        Printer.Print("}\n");
                    }
                    #endregion

                    #endregion
                }
                    
                return true;
                    
            }
            catch (System.Exception e)
            {
                Console.WriteLine(e.Message);
                return false;
            }
        }

        public bool Run()
        {
            if (!GenerateCSharpFile())
                return false;

            //if (!GenerateCPlusPlusFile())
            //    return false;

            return true;
        }
    }
}
